// src/user/user.controller.ts
import {
  Controller,
  Post,
  Get,
  Body,
  HttpStatus,
  Res,
  Query,
} from '@nestjs/common';
import { User, JwtUser } from '@/common/decorators/current-user.decorator';
import { Response } from 'express';
import { UserService } from './user.service';
import { userErrorMessages } from '../common/services/validation.service';
import {
  CreateUserByEmailDto,
  CheckPhoneNumberForGenVeriCode,
  CreateByPhoneNumDto,
} from './dto/create-user.dto';
import { RedisService } from '@/common/redis/redis.service';
import {
  ValidationException,
  ValidationTokenException,
  ErrorResponseException,
} from '@/common/exceptions/custom-exception';
import { Public } from '@/auth/decorators/public.decorator';
import { AuthService } from '@/auth/auth.service';
import configuration from '@/config/configuration';

@Controller('users')
export class UserController {
  constructor(
    private readonly userService: UserService,
    private readonly authService: AuthService,
    private readonly redisService: RedisService,
  ) {}

  @Public()
  @Post('create')
  async createByEmail(@Body() createUserByEmailDto: CreateUserByEmailDto) {
    const isUserExist = await this.userService.IsUserExist(
      createUserByEmailDto.username,
    );
    if (isUserExist) {
      throw new ValidationException('createUserAlreadyExists');
    }
    const user = await this.userService.createByEmail(createUserByEmailDto);
    return user;
  }

  @Public()
  @Post('loginByEmail')
  async loginByEmail(@Body() loginInfo: CreateUserByEmailDto) {
    const user = await this.userService.findByUsername(
      loginInfo.username,
      loginInfo.password,
    );
    if (!user) {
      throw new ValidationException('loginCheckFailInfo');
    }
    const { access_token } = await this.authService.signIn(
      user._id,
      user.id,
      user.username,
      user.role,
    );

    return { id: user.id, username: user.username, access_token };
  }

  @Get('getUserInfo')
  async getUserInfo(@User() userInfo: JwtUser) {
    if (!userInfo || !userInfo.id) {
      throw new ValidationTokenException();
    }
    const user = await this.userService.findById(userInfo.id);
    return user;
  }

  @Public()
  @Post('genVeriCode')
  async genVeriCode(@Body() { phoneNumber }: CheckPhoneNumberForGenVeriCode) {
    const preVeriCode = await this.redisService.get(
      `phoneVeriCode-${phoneNumber}`,
    );
    if (preVeriCode) {
      throw new ErrorResponseException(
        userErrorMessages.phoneVeriCodeAlreadyExists,
        HttpStatus.OK,
      );
    }
    const veriCode = Math.floor(Math.random() * 9000 + 1000).toString();
    await this.redisService.set(`phoneVeriCode-${phoneNumber}`, veriCode, 60);
    return { veriCode };
  }

  @Public()
  @Post('loginByPhoneNumber')
  async loginByPhoneNumber(
    @Body() { phoneNumber, veriCode }: CreateByPhoneNumDto,
  ): Promise<any> {
    const redis_veriCode = await this.redisService.get(
      `phoneVeriCode-${phoneNumber}`,
    );
    if (veriCode !== redis_veriCode) {
      throw new ErrorResponseException(
        userErrorMessages.veriCodeError,
        HttpStatus.OK,
      );
    }
    const isUserExist = await this.userService.IsUserExist(phoneNumber);
    if (!isUserExist) {
      return this.userService.createByPhoneNumber({ phoneNumber });
    }
    const user = await this.userService.findByPhoneNumber({ phoneNumber });
    if (!user) {
      throw new ValidationException('loginCheckFailInfo');
    }
    const { access_token } = await this.authService.signIn(
      user._id,
      user.id,
      user.username,
      user.role,
    );
    return { ...user, access_token };
  }

  @Public()
  @Get('passport/github')
  async oauth(@Res() res: Response) {
    const githubOauth2Config = configuration().Oauth2.github;
    res.redirect(
      `${githubOauth2Config.oauthUrl}?client_id=${githubOauth2Config.client_id}&redirect_uri=${githubOauth2Config.redirectUrl}`,
    );
  }

  @Public()
  @Get('passport/github/callback')
  async oauthByGithub(@Query() query, @Res() res: Response) {
    try {
      const user = await this.userService.loginByGithub(query.code);
      const { access_token } = await this.authService.signIn(
        user._id,
        user.id,
        user.username,
        user.role,
      );
      // return { ...user, access_token };
      res.setHeader('Content-Type', 'text/html');
      res.send(`<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <h1>登录成功，跳转中</h1>
    <script>
        window.onload = function () {
            setTimeout(() => {
                window.opener.postMessage('${access_token}', 'http://localhost:5173/')
                window.close()
            }, 2000);
        }
    </script>
</body>

</html>`);
    } catch (error) {
      throw new ErrorResponseException(
        userErrorMessages.githubOauthError,
        HttpStatus.OK,
      );
    }
  }
}
